//
//  ContentView.swift
//  crossLanguage
//
//  Created by Yao Yuan on 6/4/2023.
//

import SwiftUI

struct ContentView: View {
    var body: some View {
        VStack {
            Image(systemName: "globe")
                .imageScale(.large)
                .foregroundColor(.accentColor)
            Text(testFunc())
        }
        .padding()
    }
    
    // Minimum cases
    // Aims to test Swift -> C++ cost
    // Simply call C++ function through Objective-C
    // with passing 1 to 10 numbers of primitive parameters
    func simpleCallInteger(LOOPCOUNT: Int) {
        let info = ProcessInfo.processInfo;
        let begin = info.systemUptime;
        for _ in 0..<LOOPCOUNT
        {
            HelloWorldWrapper().benchmarkZero();
            HelloWorldWrapper().benchmarkOne(1);
            HelloWorldWrapper().benchmarkTwo(1, 2);
            HelloWorldWrapper().benchmarkThree(1, 2, 3);
            HelloWorldWrapper().benchmarkFour(1, 2, 3, 4);
            HelloWorldWrapper().benchmarkFive(1, 2, 3, 4, 5);
            HelloWorldWrapper().benchmarkSix(1, 2, 3, 4, 5, 6);
            HelloWorldWrapper().benchmarkSeven(1, 2, 3, 4, 5, 6, 7);
            HelloWorldWrapper().benchmarkEight(1, 2, 3, 4, 5, 6, 7, 8);
            HelloWorldWrapper().benchmarkNine(1, 2, 3, 4, 5, 6, 7, 8, 9);
            HelloWorldWrapper().benchmarkTen(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
        }
        let end = info.systemUptime;
        print("Benchmark - Swift - simpleCallInteger - running " + String(LOOPCOUNT) + " times cost is " + String((end - begin - forLoopTime(LOOPCOUNT:LOOPCOUNT))*1000) + " ms");
    }
    
    // Minimum cases
    // Aims to test Swift -> C++ cost
    // Simply call C++ function through Objective-C
    // with passing 1 to 10 numbers of object
    func simpleCallObject(LOOPCOUNT: Int) {
        let sampleObj = CustomObject();
        sampleObj.value1 = "1";
        sampleObj.value2 = "2";
        sampleObj.value3 = "3";
        let info = ProcessInfo.processInfo;
        let begin = info.systemUptime;
        for _ in 0..<LOOPCOUNT
        {
            HelloWorldWrapper().benchmarkZero();
            HelloWorldWrapper().benchmarkObjectOne(sampleObj);
            HelloWorldWrapper().benchmarkObjectTwo(sampleObj, sampleObj);
            HelloWorldWrapper().benchmarkObjectThree(sampleObj, sampleObj, sampleObj);
            HelloWorldWrapper().benchmarkObjectFour(sampleObj, sampleObj, sampleObj, sampleObj);
            HelloWorldWrapper().benchmarkObjectFive(sampleObj, sampleObj, sampleObj, sampleObj, sampleObj);
            HelloWorldWrapper().benchmarkObjectSix(sampleObj, sampleObj, sampleObj, sampleObj, sampleObj, sampleObj);
            HelloWorldWrapper().benchmarkObjectSeven(sampleObj, sampleObj, sampleObj, sampleObj, sampleObj, sampleObj, sampleObj);
            HelloWorldWrapper().benchmarkObjectEight(sampleObj, sampleObj, sampleObj, sampleObj, sampleObj, sampleObj, sampleObj, sampleObj);
            HelloWorldWrapper().benchmarkObjectNine(sampleObj, sampleObj, sampleObj, sampleObj, sampleObj, sampleObj, sampleObj, sampleObj, sampleObj);
            HelloWorldWrapper().benchmarkObjectTen(sampleObj, sampleObj, sampleObj, sampleObj, sampleObj, sampleObj, sampleObj, sampleObj, sampleObj, sampleObj);
        }
        let end = info.systemUptime;
        print("Benchmark - Swift - simpleCallObject - running " + String(LOOPCOUNT) + " times cost is " + String((end - begin - forLoopTime(LOOPCOUNT:LOOPCOUNT))*1000) + " ms");
    }
    
    // Complex callbacks
    // Aims to test Swift -> C++ Cost
    // Pass a Swift callback to C++ and execute callback
    func complexCallBack(LOOPCOUNT: Int) {
        func swiftCallback() {
        }
        let info = ProcessInfo.processInfo;
        let begin = info.systemUptime;
        for _ in 0..<LOOPCOUNT
        {
            HelloWorldWrapper().executeCallBack(swiftCallback);
        }
        let end = info.systemUptime;
        print("Benchmark - Swift - complexCallBack - running " + String(LOOPCOUNT) + " times cost is " + String((end - begin - forLoopTime(LOOPCOUNT:LOOPCOUNT))*1000) + " ms");
    }
    
    // Complex Setting Value - light workload - one object
    // Aims to test Swift -> C++ cost
    // Pass a Swift Class to C++ and change and return the value to Swift
    func complexSettingValue(LOOPCOUNT: Int) {
        let sampleObj = CustomObject();
        sampleObj.value1 = "1";
        sampleObj.value2 = "1";
        sampleObj.value3 = "1";
        let info = ProcessInfo.processInfo;
        let begin = info.systemUptime;
        for _ in 0..<LOOPCOUNT
        {
            HelloWorldWrapper().benchmarkSettingValue(sampleObj);
        }
        let end = info.systemUptime;
        print("Benchmark - Swift - complexSettingValue - running " + String(LOOPCOUNT) + " times cost is " + String((end - begin - forLoopTime(LOOPCOUNT:LOOPCOUNT))*1000) + " ms");
    }
    
    // Complex Setting Value - heavy workload - large array
    // Aims to test Swift -> C++ -> Swift cost
    // Pass a Swift Array to C, change values at Objective-C
    func complexSettingLargeArrayValue(LOOPCOUNT: Int) {
        let size = 5000;
        let largeArray = [Int](repeating: 0, count: size);
        let info = ProcessInfo.processInfo;
        let begin = info.systemUptime;
        for _ in 0..<LOOPCOUNT
        {
            let _ = HelloWorldWrapper().benchmarkSettingLargeArray(largeArray, size);
        }
        let end = info.systemUptime;
        print("Benchmark - Swift - complexSettingLargeArrayValue - running " + String(LOOPCOUNT) + " times cost is " + String((end - begin - forLoopTime(LOOPCOUNT:LOOPCOUNT))*1000) + " ms");
    }
    
    // Complex C++ Class
    // Aims to test C++ -> Swift cost
    // Pass a C++ constructor to Swift and create a new instance at Swift layer
    func complexCppConstructor(LOOPCOUNT: Int) {
        let info = ProcessInfo.processInfo;
        let begin = info.systemUptime;
        for _ in 0..<LOOPCOUNT
        {
            let _ = HelloWorldWrapper();
        }
        let end = info.systemUptime;
        print("Benchmark - Swift - complexCppConstructor - running " + String(LOOPCOUNT) + " times cost is " + String((end - begin - forLoopTime(LOOPCOUNT:LOOPCOUNT))*1000) + " ms");
    }
    
    // Complex C++ Class
    // Aims to test Swift -> C++ methods
    // Create a C++ class instance and call its method
    func complexCppMethod(LOOPCOUNT: Int) {
        let wrapper = HelloWorldWrapper();
        let info = ProcessInfo.processInfo;
        let begin = info.systemUptime;
        for _ in 0..<LOOPCOUNT
        {
            wrapper.sayHello();
        }
        let end = info.systemUptime;
        print("Benchmark - Swift - complexCppMethod - running " + String(LOOPCOUNT) + " times cost is " + String((end - begin - forLoopTime(LOOPCOUNT:LOOPCOUNT))*1000) + " ms");
    }

    func forLoopTime(LOOPCOUNT: Int) -> Double{
        let info = ProcessInfo.processInfo;
        let begin = info.systemUptime;
        for _ in 0..<LOOPCOUNT
        {
            // do-nothing
        }
        return (info.systemUptime - begin);
    }
    
    func testFunc() -> String {
        print("Swift Benchmark tests start");
        let LOOPCOUNT: Int = 10000;

        simpleCallInteger(LOOPCOUNT: LOOPCOUNT);

        simpleCallObject(LOOPCOUNT: LOOPCOUNT);
        
        complexCallBack(LOOPCOUNT: LOOPCOUNT);
        
        complexSettingValue(LOOPCOUNT: LOOPCOUNT);
        
        complexSettingLargeArrayValue(LOOPCOUNT: 10);
        
        complexCppConstructor(LOOPCOUNT: LOOPCOUNT);
        
        complexCppMethod(LOOPCOUNT: LOOPCOUNT);
        
        let result: String = HelloWorldWrapper().sayHello();
        return result;
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
